package com.blog.backend.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.blog.backend.constant.BlogConstant;
import com.blog.backend.domain.BlogInfo;
import com.blog.backend.domain.DTO.BlogDTO;
import com.blog.backend.domain.DTO.UserDTO;
import com.blog.backend.mapper.BlogMapper;
import com.blog.backend.service.BlogService;
import com.blog.common.core.domain.R;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Auman
 * @time 2024/4/28 10:09
 */
@Service
public class BlogServiceImpl implements BlogService {

    private static final Logger logger = LoggerFactory.getLogger(BlogServiceImpl.class);

    @Autowired
    private BlogMapper mapper;

    @Autowired
    private ElasticsearchRestTemplate esTemplate;

    @Override
    public int newBlog(BlogDTO dto) {
        BlogInfo info = new BlogInfo();
        BeanUtils.copyProperties(dto, info);
        String code = "B" + new Date().getTime()+dto.getBelongCode();
        info.setCode(code);
        return mapper.insert(info);
    }

    @Override
    public int updateBlog(BlogDTO dto) {
        LambdaUpdateWrapper<BlogInfo> wrapper = new LambdaUpdateWrapper<>();
        BlogInfo info = new BlogInfo();
        BeanUtils.copyProperties(dto, info);
        wrapper.eq(BlogInfo::getBelongCode, dto.getBelongCode()).eq(BlogInfo::getCode, dto.getCode());
        return mapper.update(info, wrapper);
    }

    @Override
    public R updateDelBlog(BlogDTO dto) {
        BlogInfo info = new BlogInfo();
        LambdaQueryWrapper<BlogInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BlogInfo::getBelongCode, dto.getBelongCode()).eq(BlogInfo::getCode, dto.getCode());
        if (dto.getType() == 0) { //更新
            Integer id = mapper.selectOne(new LambdaQueryWrapper<BlogInfo>().eq(BlogInfo::getCode, dto.getCode())).getId();
            BeanUtils.copyProperties(dto, info);
            info.setId(id);
            return mapper.updateById(info)>0?R.ok():R.fail();
        }
        else if (dto.getType() == 1) {//放入回收站
            LambdaUpdateWrapper<BlogInfo> wrapper2 = new LambdaUpdateWrapper<>();
            wrapper2.eq(BlogInfo::getBelongCode, dto.getBelongCode())
                    .eq(BlogInfo::getCode, dto.getCode())
                    .set(BlogInfo::getStatus, BlogConstant.RECYCLE);
            return mapper.update(null,wrapper2)>0?R.ok():R.fail();
        }
        else if (dto.getType() == 4) {//取回本人在回收站的博客
            LambdaUpdateWrapper<BlogInfo> wrapper2 = new LambdaUpdateWrapper<>();
            wrapper2.eq(BlogInfo::getBelongCode, dto.getBelongCode())
                    .eq(BlogInfo::getCode, dto.getCode())
                    .set(BlogInfo::getStatus, BlogConstant.PUBLISHED);
            return mapper.update(null,wrapper2)>0?R.ok():R.fail();
        }
        else if (dto.getType() == 2) {//直接删除
            return mapper.delete(wrapper)>0?R.ok():R.fail();
        }
        else {
            return R.ok("无操作");
        }
    }

    @Override
    public List<BlogInfo> getBlog(UserDTO dto) {
        return mapper.getByType(dto);
    }

    @Override
    public List<BlogInfo> searchByInfo(BlogDTO dto) {
        return mapper.searchByInfo(dto);
    }

    @Override
    public List<BlogInfo> getByTitle7Content(BlogDTO dto) {
        try {
            if (dto == null || dto.getTitle() == null || dto.getContent() == null) {
                logger.warn("Input DTO is null or lacks search data");
                return Collections.emptyList();
            }

            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getTitle(), "title"));
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(dto.getContent(), "content"));
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery(BlogConstant.PUBLISHED, "status"));

            NativeSearchQuery query = new NativeSearchQueryBuilder()
                    .withQuery(boolQueryBuilder)
                    .withHighlightFields(
                            new HighlightBuilder.Field("title").preTags("<span style='color:red;'>").postTags("</span>"),
                            new HighlightBuilder.Field("content").preTags("<span style='color:red;'>").postTags("</span>"))
                    .build();

            SearchHits<BlogInfo> searchHits = esTemplate.search(query, BlogInfo.class);

            if (searchHits.getTotalHits() == 0) {
                return Collections.emptyList();
            }

            return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("Elasticsearch query error: ", e);
            return Collections.emptyList();
        }
    }
}
